using AutoMapper;
using B.S.NewMedical.Api.Write.Application.Command.ContentManagement.Registration;
using B.S.NewMedical.Domain.Appointment;
using B.S.NewMedical.Domain.Hospital;
using B.S.NewMedical.Infrastructure.Interface;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace B.S.NewMedical.Api.Write.Application.Handler.ContentManagement.Registration
{
    /// <summary>
    /// 添加挂号命令处理器
    /// </summary>
    public class AddRegistrationCommandHandler : IRequestHandler<AddRegistrationCommand, int>
    {
        private readonly IMapper _mapper;
        private readonly IBaseRepository<B.S.NewMedical.Domain.Appointment.Registration> _registrationRepository;
        private readonly IBaseRepository<MedicalCard> _medicalCardRepository;
        private readonly IBaseRepository<PatientModel> _patientRepository;
        private readonly IBaseRepository<B.S.NewMedical.Domain.Appointment.Doctor> _doctorRepository;

        public AddRegistrationCommandHandler(
            IMapper mapper,
            IBaseRepository<B.S.NewMedical.Domain.Appointment.Registration> registrationRepository,
            IBaseRepository<MedicalCard> medicalCardRepository,
            IBaseRepository<PatientModel> patientRepository,
            IBaseRepository<B.S.NewMedical.Domain.Appointment.Doctor> doctorRepository)
        {
            _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
            _registrationRepository = registrationRepository ?? throw new ArgumentNullException(nameof(registrationRepository));
            _medicalCardRepository = medicalCardRepository ?? throw new ArgumentNullException(nameof(medicalCardRepository));
            _patientRepository = patientRepository ?? throw new ArgumentNullException(nameof(patientRepository));
            _doctorRepository = doctorRepository ?? throw new ArgumentNullException(nameof(doctorRepository));
        }

        /// <summary>
        /// 处理添加挂号命令
        /// </summary>
        /// <param name="request">添加挂号命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>新增的挂号ID</returns>
        public async Task<int> Handle(AddRegistrationCommand request, CancellationToken cancellationToken)
        {
            // 验证就诊日期不能是过去的日期
            if (request.Visit_date.Date < DateTime.Today)
            {
                throw new ArgumentException("就诊日期不能是过去的日期");
            }

            // 验证患者是否存在
            var patient = await _patientRepository.GetAll()
                .Where(p => p.Id == request.Patient_id && !p.IsDeleted)
                .FirstOrDefaultAsync(cancellationToken);

            if (patient == null)
            {
                throw new ArgumentException($"患者ID '{request.Patient_id}' 不存在");
            }

            // 获取患者的医疗卡信息
            string cardNo;
            MedicalCard medicalCard;

            if (string.IsNullOrWhiteSpace(request.Card_no))
            {
                // 如果没有提供卡号，根据患者ID查询医疗卡
                medicalCard = await _medicalCardRepository.GetAll()
                    .Where(c => c.Patient_id == request.Patient_id && !c.IsDeleted && c.Status == "正常")
                    .FirstOrDefaultAsync(cancellationToken);

                if (medicalCard == null)
                {
                    throw new ArgumentException($"患者ID '{request.Patient_id}' 没有有效的医疗卡");
                }

                cardNo = medicalCard.Card_no;
            }
            else
            {
                // 如果提供了卡号，验证卡号是否存在且状态正常
                medicalCard = await _medicalCardRepository.GetAll()
                    .Where(c => c.Card_no == request.Card_no && !c.IsDeleted)
                    .FirstOrDefaultAsync(cancellationToken);

                if (medicalCard == null)
                {
                    throw new ArgumentException($"就诊卡号 '{request.Card_no}' 不存在");
                }

                if (medicalCard.Status != "正常")
                {
                    throw new ArgumentException($"就诊卡状态异常，无法挂号。当前状态：{medicalCard.Status}");
                }

                // 验证就诊卡是否绑定的是该患者
                if (medicalCard.Patient_id != request.Patient_id)
                {
                    throw new ArgumentException("就诊卡与患者信息不匹配");
                }

                cardNo = request.Card_no;
            }

            // 验证医生是否存在且状态正常
            var doctor = await _doctorRepository.GetAll()
                .Where(d => d.Id == request.Doctor_id && !d.IsDeleted)
                .FirstOrDefaultAsync(cancellationToken);

            if (doctor == null)
            {
                throw new ArgumentException($"医生ID '{request.Doctor_id}' 不存在");
            }

            // 检查该患者是否已在同一天同一医生处挂号
            var existingRegistration = await _registrationRepository.GetAll()
                .Where(r => r.Patient_id == request.Patient_id 
                           && r.Doctor_id == request.Doctor_id 
                           && r.Visit_date.Date == request.Visit_date.Date 
                           && r.Status == "待就诊"
                           && !r.IsDeleted)
                .FirstOrDefaultAsync(cancellationToken);

            if (existingRegistration != null)
            {
                throw new ArgumentException("该患者已在当天该医生处挂号，不能重复挂号");
            }

            // 生成当日流水号
            var slotNo = await GenerateSlotNumber(request.Doctor_id, request.Visit_date.Date);

            // 创建挂号记录
            var registration = new B.S.NewMedical.Domain.Appointment.Registration
            {
                Card_no = cardNo, // 使用查询到的或验证过的卡号
                Patient_id = request.Patient_id,
                Doctor_id = request.Doctor_id,
                dept_id = request.Dept_id,
                Visit_date = request.Visit_date,
                Slot_no = slotNo,
                Fee = request.Fee,
                Status = "待就诊",
                Create_time = DateTime.Now
            };

            // 保存挂号记录
            await _registrationRepository.CreateAsync(registration);

            return registration.Id;
        }

        /// <summary>
        /// 生成当日流水号
        /// </summary>
        /// <param name="doctorId">医生ID</param>
        /// <param name="visitDate">就诊日期</param>
        /// <returns>流水号</returns>
        private async Task<int> GenerateSlotNumber(int doctorId, DateTime visitDate)
        {
            // 查询该医生当天已有的挂号数量
            var existingCount = await _registrationRepository.GetAll()
                .Where(r => r.Doctor_id == doctorId 
                           && r.Visit_date.Date == visitDate.Date 
                           && !r.IsDeleted)
                .CountAsync();

            // 返回下一个流水号
            return existingCount + 1;
        }
    }
} 